<!--
 * @description 瀑布流组件
 * @author: 陈陈
 * @date: 2025/05/09
 * @phone: 18560000860
 * @email: 18560000860@qq.com
 * @company: 济南晨霜信息技术有限公司 /
 * @business: 承接前后端项目的开发
-->
<template>
	<view class="pure-waterfall" :class="_classes" :style="_styles">
		<slot></slot>
	</view>
</template>

<script>
import commonComponentOptions from "../../config/common-component-options";
export default {
	options: commonComponentOptions,
};
</script>

<script setup>
import { ref, computed, provide } from "vue";
import props from "./props";
import { sleep } from "../../functions/common";

// **************************************************************************************************************
// * Refs
// **************************************************************************************************************
// 待更新队列
let _queue = [];
// 所有子元素的布局信息
const _rects = ref({});
// 所有子元素的节点信息
const _doms = ref({});
// 是否正在布局中
const _isLayouting = ref(false);
// 容器高度
const _height = ref(0);

// **************************************************************************************************************
// * Options
// **************************************************************************************************************
defineOptions(commonComponentOptions);

// **************************************************************************************************************
// * Props
// **************************************************************************************************************
const _props = defineProps(props);

// **************************************************************************************************************
// * Emits
// **************************************************************************************************************
const _emits = defineEmits([]);

// **************************************************************************************************************
// * Classes
// **************************************************************************************************************
const _classes = computed(() => {
	const array = [];
	return array;
});

// **************************************************************************************************************
// * Styles
// **************************************************************************************************************
const _styles = computed(() => {
	const array = [];

	// 列数
	array.push(`--pure-waterfall-cols: ${_props.cols};`);

	// 间隔
	array.push(`--pure-waterfall-gap: ${_props.gap};`);

	// 高度
	array.push(
		`height: calc(${_height.value}px - var(--pure-waterfall-gap) / 2);`
	);

	return array;
});

// **************************************************************************************************************
// * Computed
// **************************************************************************************************************

// **************************************************************************************************************
// * Functions
// **************************************************************************************************************
// 添加子元素节点信息
function _addDom(dom) {
	// 存储节点信息
	_doms.value[dom.uuid] = dom;

	// 添加到待更新队列中
	_queue.push(dom);

	// 未在布局中，更新布局
	if (!_isLayouting.value) _updateLayout();
}

// 删除子元素节点信息
function _deleteDom(uuid) {
	// 删除节点信息
	delete _doms.value[uuid];

	// 添加到待更新队列中
	_queue.push(uuid);

	// 未在布局中，更新布局
	if (!_isLayouting.value) _updateLayout();
}

// 更新布局
async function _updateLayout() {
	// 更新布局状态
	_isLayouting.value = true;

	// 清空布局队列
	_queue = [];

	// 重新计算所有子元素的布局信息
	let rects = {};

	// 将 _doms 按 key 从小到大排序
	let doms = Object.values(_doms.value).sort((a, b) => {
		return a.index - b.index;
	});

	// 列高度
	const heights = Array(_props.cols).fill(0);

	// 遍历所有子元素
	doms.forEach((dom) => {
		// 最小列的下标
		let minColIndex = heights.indexOf(Math.min(...heights));

		// 最小列的高度
		let minColHeight = heights[minColIndex];

		// 当前子元素的高度
		let height = dom?.height || 0;

		// 计算子元素布局信息
		const rect = {
			colIndex: minColIndex, // 所属列
			top: minColHeight, // 距离顶部的距离
			isInited: true, // 是否已初始化
			isUpdate: _rects.value?.[dom?.uuid]?.isInited, // 是否更新位置
		};
		rects[dom.uuid] = rect;

		// 更新最小列的高度
		heights[minColIndex] = minColHeight + height;

		// 更新容器高度
		_height.value = Math.max(...heights);
	});

	// 更新布局信息
	_rects.value = rects;

	// 继续计算
	// 等待一下，节省一点性能
	await sleep(100);

	// 更新布局状态
	_isLayouting.value = false;

	// 如果队列不为空，则继续计算
	if (_queue.length > 0) _updateLayout();
}

// **************************************************************************************************************
// * Provides
// **************************************************************************************************************
provide("AddPureWaterfallChildrenDOM", _addDom);
provide("DeletePureWaterfallChildrenDOM", _deleteDom);
provide("PureWaterfallChildrenRects", _rects);
provide(
	"PureWaterfallCols",
	computed(() => _props.cols)
);
provide(
	"PureWaterfallGap",
	computed(() => _props.gap)
);
</script>

<style scoped lang="scss">
@import "./style.scss";
</style>
